package com.slipper.core.tree;

import com.slipper.constants.Constants;
import com.slipper.util.Tool;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

public class TreeUtil {
    /**
     * 根据给定的列表生成树
     */
    public static Node buildTree(TreeInfo treeInfo, List<?> list) {
        return buildTree(treeInfo, list, null);
    }

    /**
     * 根据给定的列表生成树
     */
    public static Node buildTree(TreeInfo treeInfo, List<?> list, String sortType) {
        if (list == null) {
            return null;
        }
        Node rootNode = new Node(treeInfo.getRootId(), treeInfo.getNodeName(), treeInfo.getRootHref());
        rootNode.setData(treeInfo.getData());
        List<Node> nodeList = buildNode(treeInfo, list, sortType);
        resetRootNode(treeInfo.getRootId(), nodeList);
        buildChildren(rootNode, nodeList);
        return rootNode;
    }

    public static void resetRootNode(Serializable rootId, List<Node> nodeList) {
        for (Node node : nodeList) {
            if (Tool.isBlank(node.getPid())) {
                node.setPid(rootId);
                continue;
            }
            if (nodeList.stream().noneMatch(item -> node.getPid().equals(item.getId()))) {
                node.setPid(rootId);
            }
        }
    }

    /**
     * 根据给定的列表生成节点
     */
    public static List<Node> buildNode(TreeInfo treeInfo, List<?> list) {
        return buildNode(treeInfo, list, null);
    }

    /**
     * 根据给定的列表生成节点
     */
    public static List<Node> buildNode(TreeInfo treeInfo, List<?> list, String sortType) {
        List<Node> nodeList = new ArrayList<>();
        for (Object object : list) {
            Node node;
            if (object instanceof Map) {
                node = buildMapNode(treeInfo, (Map<?, ?>) object, sortType);
            } else {
                node = buildBeanNode(treeInfo, object, sortType);
            }
            if (Tool.isNotBlank(treeInfo.getNodeType())) {
                node.setType(treeInfo.getNodeType());
            }
            node.setLazy(treeInfo.isLazy());
            nodeList.add(node);
        }

        return nodeList;
    }

    public static Node buildBeanNode(TreeInfo treeInfo, Object object, String sortType) {
        BeanWrapper beanWrap = new BeanWrapperImpl(object);
        Serializable id = (Serializable) beanWrap.getPropertyValue(treeInfo.getIdField());
        Serializable pid;
        if (Tool.isBlank(treeInfo.getPidField())) {
            pid = treeInfo.getRootId();
        } else {
            pid = (Serializable) beanWrap.getPropertyValue(treeInfo.getPidField());
        }
        if (Tool.isBlank(pid)) {
            pid = Constants.ROOT_ID;
        }
        String text = Tool.isBlank(treeInfo.getTextField())
                ? null : (String) beanWrap.getPropertyValue(treeInfo.getTextField());
        String type = Tool.isBlank(treeInfo.getTypeField())
                ? null : (String) beanWrap.getPropertyValue(treeInfo.getTypeField());
        String href = null;
        if (Tool.isBlank(treeInfo.getHref())) {
            if (Tool.isNotBlank(treeInfo.getHrefField())) {
                href = (String) beanWrap.getPropertyValue(treeInfo.getHrefField());
            }
        } else {
            href = treeInfo.getHref();
        }
        Integer orderBy = Tool.isBlank(treeInfo.getSortField()) ? Integer.valueOf(0)
                : (Integer) beanWrap.getPropertyValue(treeInfo.getSortField());

        if (Tool.isNotBlank(href)) {
            href = href.replace("{idPropertyKeyValue}", String.valueOf(id));
            href = href.replace("{pidPropertyKeyValue}", String.valueOf(pid));
        }
        if (treeInfo.isConcatIdWithPid()) {
            id = pid + "@" + id;
        }
        return new Node(id, pid, text, type, href, orderBy, sortType, treeInfo.canNotOp(), object);
    }

    public static Node buildMapNode(TreeInfo treeInfo, Map<?, ?> map, String sortType) {
        Serializable id = (Serializable) map.get(treeInfo.getIdField());
        Serializable pid;
        if (Tool.isBlank(treeInfo.getPidField())) {
            pid = treeInfo.getRootId();
        } else {
            pid = (Serializable) map.get(treeInfo.getPidField());
        }
        if (Tool.isBlank(pid)) {
            pid = Constants.ROOT_ID;
        }
        String text = treeInfo.getTextField() == null
                ? null : (String) map.get(treeInfo.getTextField());
        String type = Tool.isBlank(treeInfo.getTypeField())
                ? null : (String) map.get(treeInfo.getTypeField());
        String href = null;
        if (treeInfo.getHref() == null) {
            if (treeInfo.getHrefField() != null) {
                href = (String) map.get(treeInfo.getHrefField());
            }
        } else {
            href = treeInfo.getHref();
        }

        Object orderByStr = treeInfo.getSortField() == null ? null : map.get(treeInfo.getSortField());
        Integer orderBy = orderByStr == null ? 0 : Integer.parseInt(orderByStr.toString());

        if (href != null) {
            href = href.replace("{idPropertyKeyValue}", String.valueOf(id));
            href = href.replace("{pidPropertyKeyValue}", String.valueOf(pid));
        }
        if (treeInfo.isConcatIdWithPid()) {
            id = pid + "@" + id;
        }
        return new Node(id, pid, text, type, href, orderBy, sortType, treeInfo.canNotOp(), map);
    }

    /**
     * 将nodeList中属于parentNode的子节点设置到parentNode子节点中
     */
    public static void buildChildren(Node parentNode, List<Node> nodeList) {
        for (Node currentNode : nodeList) {
            if (!currentNode.getId().equals(currentNode.getPid())
                    && parentNode.getId().equals(currentNode.getPid())) {
                parentNode.addChildren(currentNode);
                buildChildren(currentNode, nodeList);
            }
        }
    }

    /**
     * 根据给定的列表生成树
     * @param sortType 排序
     * @param trees 树信息
     */
    public static Node buildTree(String sortType, Tree ...trees) {
        if (trees.length == 0) {
            return null;
        }
        if (trees[0].getTreeInfo() == null) {
            return null;
        }

        TreeInfo treeInfo = trees[0].getTreeInfo();
        Node rootNode = new Node(treeInfo.getRootId(), treeInfo.getNodeName(), treeInfo.getRootHref());
        rootNode.setData(treeInfo.getData());
        List<Node> nodeList = buildNode(treeInfo, trees[0].getDataList(), sortType);
        for (int i=1; i<trees.length; i++) {
            nodeList.addAll(buildNode(trees[i].getTreeInfo(), trees[i].getDataList(), sortType));
        }
        buildChildren(rootNode, nodeList);
        return rootNode;
    }
}
